package com.light.service;

import com.light.constant.Constant;

import javax.swing.*;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @Author MoonlightL
 * @ClassName: DownloadService
 * @ProjectName downloader
 * @Description: 下载业务
 * @DateTime 2023/3/10, 0010 18:13
 */
public class DownloadService {

    private ExecutorService service = Executors.newFixedThreadPool(8);

    public void downloadFile(String url, String dir, JTextArea textArea) throws Exception {

        URL newUrl = new URL(url);
        String[] arr = newUrl.getPath().split("/");
        String fullName = arr[arr.length - 1];
        String fileName = fullName.substring(0, fullName.lastIndexOf("."));

        URLConnection connection = newUrl.openConnection();
        int resourceSize = connection.getContentLength();
        int num = 1;
        if (resourceSize > Constant.SIZE) {
            num = (resourceSize % Constant.SIZE) == 0 ? resourceSize / Constant.SIZE : resourceSize / Constant.SIZE + 1;
        }

        Integer totalNum = num;
        CountDownLatch countDownLatch = new CountDownLatch(totalNum);
        textArea.append("开始下载文件\r\n");
        for (int i = 0; i < totalNum; i++) {
            int finalIndex = i;
            this.service.submit(() -> {
                int start = finalIndex * Constant.SIZE;
                int end = finalIndex * Constant.SIZE + Constant.SIZE - 1;
                InputStream is = null;
                FileOutputStream os = null;
                try {
                    URLConnection con = newUrl.openConnection();
                    con.setRequestProperty("Range", "bytes=" + start + "-" + end);
                    is = con.getInputStream();
                    os = new FileOutputStream(new File(dir + fileName + "_" + this.checkIndex(finalIndex) + ".tmp"));
                    byte[] bytes = new byte[1024];
                    int len = 0;
                    while ((len = is.read(bytes)) != -1) {
                        os.write(bytes, 0, len);
                    }
                    // 计数
                    countDownLatch.countDown();
                    double process = BigDecimal.valueOf(totalNum - countDownLatch.getCount())
                            .divide(BigDecimal.valueOf(totalNum), 2, RoundingMode.HALF_DOWN)
                            .multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN).doubleValue();
                    textArea.append("下载进度：" + process + "%\r\n");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        os.close();
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        // 等待下载完毕
        countDownLatch.await();
        textArea.append("开始合并文件\r\n");
        // 合并文件
        String targetPath = this.mergeFile(dir, fullName, fileName);
        textArea.append("合并文件完毕: " + targetPath + " \r\n");
    }

    private static String checkIndex(int index) {
        String repeatStr = "";
        int repeatNum = 7 - String.valueOf(index).length();
        if (repeatNum > 0) {
            for (int i = 0; i < repeatNum; i++) {
                repeatStr += "0";
            }
        }
        return repeatStr + index;
    }

    private String mergeFile(String dir, String fullName, String fileName) throws Exception {
        File dirFile = new File(dir);
        File[] files = dirFile.listFiles((dir1, name) -> name.startsWith(fileName));
        List<File> fileList = Arrays.stream(files).sorted(Comparator.comparing(File::getName)).collect(Collectors.toList());
        File target = new File(dirFile, fullName);
        try(FileOutputStream os = new FileOutputStream(target)) {
            for (File file : fileList) {
                try (FileInputStream is = new FileInputStream(file)) {
                    byte[] arr = new byte[Constant.SIZE];
                    int len = 0;
                    while ((len = is.read(arr)) != -1) {
                        os.write(arr, 0, len);
                    }
                }
            }
        } finally {
            // 删除临时文件
            for (File file : files) {
                file.delete();
            }
        }

        return target.getAbsolutePath();
    }
}
